package org.zebra.file.excel.core;

import org.springframework.beans.BeanUtils;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartRequest;
import org.zebra.common.exception.ResultException;
import org.zebra.common.exception.StatusCode;
import org.zebra.file.excel.SimpleExcel;
import org.zebra.file.excel.annotation.ImportExcel;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.lang.reflect.Parameter;
import java.util.List;

/**
 * 上传 excel 解析注解
 *
 * @author zhanghongbin
 */
public class ImportExcelHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

    private SimpleExcel simpleExcel;

    public ImportExcelHandlerMethodArgumentResolver(SimpleExcel simpleExcel) {
        this.simpleExcel = simpleExcel;
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(ImportExcel.class);
    }

    @Override
    public Object resolveArgument(
            MethodParameter parameter,
            ModelAndViewContainer modelAndViewContainer,
            NativeWebRequest webRequest,
            WebDataBinderFactory webDataBinderFactory)
            throws Exception {
        Class<?> parameterType = parameter.getParameterType();
        if (!parameterType.isAssignableFrom(List.class)) {
            throw new ResultException(
                    StatusCode.UNKNOWN.getCode(),
                    "excel upload request resolver error, @ImportExcel parameter is not List " + parameterType);
        }
        // 处理自定义 readListener
        ImportExcel requestExcel = parameter.getParameterAnnotation(ImportExcel.class);
        boolean isValidate = parameter.hasParameterAnnotation(Validated.class);
        Class<? extends ExcelListener> readListenerClass = requestExcel.readListener();
        ExcelListener readListener =
                BeanUtils.instantiateClass(BeanUtils.getResolvableConstructor(readListenerClass), isValidate);
        // 获取请求文件流
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        InputStream inputStream;
        if (request instanceof MultipartRequest) {
            MultipartFile file = ((MultipartRequest) request).getFile(requestExcel.fileName());
            inputStream = file.getInputStream();
        } else {
            inputStream = request.getInputStream();
        }

        // 获取目标类型
        Class<?> excelModelClass =
                ResolvableType.forMethodParameter(parameter).getGeneric(0).resolve();
        try {
            simpleExcel.importExcel(inputStream, excelModelClass, readListener);
        } catch (Exception e) {
            boolean flag = false;
            Parameter[] parameters = parameter.getMethod().getParameters();
            for (Parameter p : parameters) {
                if (p.getType() == BindingResult.class) {
                    flag = true;
                    break;
                }
            }
            if (flag) {
                // 校验失败的数据处理 交给 BindResult
                WebDataBinder dataBinder = webDataBinderFactory.createBinder(
                        webRequest, readListener.getExcelResult().getErrorList(), "excel");
                ModelMap model = modelAndViewContainer.getModel();
                model.put(BindingResult.MODEL_KEY_PREFIX + "excel", dataBinder.getBindingResult());
            } else {
                throw e;
            }
        }
        return readListener.getExcelResult().getList();
    }
}
